/*
 * Copyright (c) 2011 Ball State University
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package edu.bsu.android.gtv.apps.bconnected.data;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;

import android.app.Activity;
import android.database.Cursor;

import edu.bsu.android.gtv.apps.bconnected.objects.Person;
import edu.bsu.android.gtv.apps.bconnected.parser.ParserFactory;
import edu.bsu.android.gtv.apps.bconnected.parser.ServiceParser;
import edu.bsu.android.gtv.apps.bconnected.util.AnalyticsUtils;
import edu.bsu.android.gtv.apps.bconnected.util.BSUPrivate;
import edu.bsu.android.gtv.apps.bconnected.util.Constants;
import edu.bsu.android.gtv.apps.bconnected.util.Crypto;

/**
 * Data layer for the {@link Person} object
 * @author Kyle Parker, University Computing Services
 */
public class PersonData {
    private static ArrayList<Person> mAdvisors;
    private static ArrayList<Person> mClassmates;
    private static ArrayList<Person> mInstructors;
    private static ArrayList<Person> mMembers;
    private static ArrayList<Person> mPerson;
    private static ArrayList<Person> mRoommates;

    /**
     * Loads an ArrayList<Person> from the service handler containing the list of advisors based on the student's BSU ID
     * @param bsuID
     * @param loginGuid - login guid used to determine whether the user is authorized to retrieve the data from the service handler
     * @param activity - used by the {@link ParserFactory} to retrieve the demo_account shared preference - this will determine what
     * 					 data source to use for the service handler.
     * @throws UnsupportedEncodingException - the encrypted BSU ID has to be encoded in order to pass as a querystring parameter
     */
    public static void initializeAdvisor(String bsuID, String loginGuid, Activity activity) 
    		throws UnsupportedEncodingException {
    	List<String> querystringParms = new ArrayList<String>(3);
    	querystringParms.add(Constants.QUERYSTRING_BSU_ID + URLEncoder.encode(bsuID, "UTF-8"));
		querystringParms.add(Constants.QUERYSTRING_LOGIN_GUID + loginGuid);

		ServiceParser parser = ParserFactory.getParser(Constants.SERVICE_TYPE_ADVISOR, querystringParms, activity);
		mAdvisors = parser.parsePerson();
    }

    /**
     * Loads an ArrayList<Person> from the service handler containing the list of classmates based on the student's BSU ID, 
     * course reference number, term and year
     * @param bsuID
     * @param crn
     * @param termNumber
     * @param termYear
     * @param loginGuid - login guid used to determine whether the user is authorized to retrieve the data from the service handler
     * @param activity - used by the {@link ParserFactory} to retrieve the demo_account shared preference - this will determine what
     * 					 data source to use for the service handler.
     * @throws UnsupportedEncodingException - the encrypted BSU ID has to be encoded in order to pass as a querystring parameter
     */
    public static void initializeClassmate(String bsuID, String crn, String termNumber, String termYear, String loginGuid, Activity activity) 
    		throws UnsupportedEncodingException {
    	List<String> querystringParms = new ArrayList<String>(5);
    	querystringParms.add(Constants.QUERYSTRING_BSU_ID + URLEncoder.encode(bsuID, "UTF-8"));
		querystringParms.add(Constants.QUERYSTRING_CRN + crn); 
		querystringParms.add(Constants.QUERYSTRING_TERM_NUM + termNumber); 
		querystringParms.add(Constants.QUERYSTRING_TERM_YEAR + termYear);
		querystringParms.add(Constants.QUERYSTRING_LOGIN_GUID + loginGuid);

		ServiceParser parser = ParserFactory.getParser(Constants.SERVICE_TYPE_CLASSMATE, querystringParms, activity);
		mClassmates = parser.parsePerson();
    }

    /**
     * Loads an ArrayList<Person> from the service handler containing the list of instructors for a course based on the 
     * course reference number, term and year
     * @param crn
     * @param termNumber
     * @param termYear
     * @param activity - used by the {@link ParserFactory} to retrieve the demo_account shared preference - this will determine what
     * 					 data source to use for the service handler.
     */
    public static void initializeInstructor(String crn, String termNumber, String termYear, Activity activity) {
    	List<String> querystringParms = new ArrayList<String>(4);
		querystringParms.add(Constants.QUERYSTRING_CRN + crn); 
		querystringParms.add(Constants.QUERYSTRING_TERM_NUM + termNumber); 
		querystringParms.add(Constants.QUERYSTRING_TERM_YEAR + termYear);

		ServiceParser parser = ParserFactory.getParser(Constants.SERVICE_TYPE_INSTRUCTOR, querystringParms, activity);
		mInstructors = parser.parsePerson();
    }

    /**
     * Loads an ArrayList<Person> from the service handler containing the list of members for an organization based on the 
     * organization ID and student's BSU ID
     * @param organizationID
     * @param bsuID
     * @param loginGuid - login guid used to determine whether the user is authorized to retrieve the data from the service handler
     * @param activity - used by the {@link ParserFactory} to retrieve the demo_account shared preference - this will determine what
     * 					 data source to use for the service handler.
     * @throws UnsupportedEncodingException - the encrypted BSU ID has to be encoded in order to pass as a querystring parameter
     */
    public static void initializeMember(String organizationID, String bsuID, String loginGuid, Activity activity) 
    		throws UnsupportedEncodingException {
    	List<String> querystringParms = new ArrayList<String>(3);
    	querystringParms.add(Constants.QUERYSTRING_ORG_ID + organizationID); 
    	querystringParms.add(Constants.QUERYSTRING_BSU_ID + URLEncoder.encode(bsuID, "UTF-8"));
		querystringParms.add(Constants.QUERYSTRING_LOGIN_GUID + loginGuid);

		ServiceParser parser = ParserFactory.getParser(Constants.SERVICE_TYPE_MEMBER, querystringParms, activity);
		mMembers = parser.parsePerson();
    }

    /**
     * Loads an ArrayList<Person> from the service handler containing the personal information for a student/employee based on 
     * the BSU ID and directory type
     * @param bsuID
     * @param directory - either "faculty" or "student"
     * @param activity - used by the {@link ParserFactory} to retrieve the demo_account shared preference - this will determine what
     * 					 data source to use for the service handler.
     * @throws UnsupportedEncodingException - the encrypted BSU ID has to be encoded in order to pass as a querystring parameter
     */
    public static void initializePerson(String bsuID, String directory, Activity activity) 
    		throws UnsupportedEncodingException {
    	List<String> querystringParms = new ArrayList<String>(4);
    	querystringParms.add(Constants.QUERYSTRING_SEARCH_BSU_ID + URLEncoder.encode(bsuID, "UTF-8"));
		querystringParms.add(Constants.QUERYSTRING_QUERY_ID + Constants.QUERY_PERSON_BSUID); 
		querystringParms.add(Constants.QUERYSTRING_DIRECTORY + directory); 

		ServiceParser parser = ParserFactory.getParser(Constants.SERVICE_TYPE_PERSON, querystringParms, activity);
		mPerson = parser.parsePerson();
    }

    /**
     * Loads an ArrayList<Person> from the service handler containing the personal information for a student/employee based on 
     * the BSU ID, the currently logged in student's BSU ID and directory type
     * @param searchBSUID - the BSU ID of the student/employee connection
     * @param studentBSUID - the BSU ID of the student currently logged into the application
     * @param directory - either "faculty" or "student"
     * @param activity - used by the {@link ParserFactory} to retrieve the demo_account shared preference - this will determine what
     * 					 data source to use for the service handler.
     * @throws UnsupportedEncodingException - the encrypted BSU ID has to be encoded in order to pass as a querystring parameter
     */
    public static void initializePerson(String searchBSUID, String studentBSUID, String directory, Activity activity) 
    		throws UnsupportedEncodingException {
    	List<String> querystringParms = new ArrayList<String>(4);
    	querystringParms.add(Constants.QUERYSTRING_SEARCH_BSU_ID + URLEncoder.encode(searchBSUID, "UTF-8"));
    	querystringParms.add(Constants.QUERYSTRING_STUDENT_BSU_ID + URLEncoder.encode(studentBSUID, "UTF-8"));
		querystringParms.add(Constants.QUERYSTRING_QUERY_ID + Constants.QUERY_PERSON_BSUID); 
		querystringParms.add(Constants.QUERYSTRING_DIRECTORY + directory); 

		ServiceParser parser = ParserFactory.getParser(Constants.SERVICE_TYPE_PERSON, querystringParms, activity);
		mPerson = parser.parsePerson();
    }

    /**
     * Loads an ArrayList<Person> from the service handler containing list of neighbors in the residence hall for a student based on 
     * the BSU ID, room, floor and hall
     * @param bsuID
     * @param roomID
     * @param floor
     * @param hall
     * @param loginGuid - login guid used to determine whether the user is authorized to retrieve the data from the service handler
     * @param activity - used by the {@link ParserFactory} to retrieve the demo_account shared preference - this will determine what
     * 					 data source to use for the service handler.
     * @throws UnsupportedEncodingException - the encrypted BSU ID has to be encoded in order to pass as a querystring parameter
     */
    public static void initializeRoommates(String bsuID, String roomID, String floor, String hall, String loginGuid, Activity activity) 
    		throws UnsupportedEncodingException {
    	List<String> querystringParms = new ArrayList<String>(5);
    	querystringParms.add(Constants.QUERYSTRING_BSU_ID + URLEncoder.encode(bsuID, "UTF-8"));
		querystringParms.add(Constants.QUERYSTRING_ROOM_ID + roomID); 
		querystringParms.add(Constants.QUERYSTRING_FLOOR_CODE + floor); 
		querystringParms.add(Constants.QUERYSTRING_HALL_CODE + hall); 
		querystringParms.add(Constants.QUERYSTRING_LOGIN_GUID + loginGuid);

		ServiceParser parser = ParserFactory.getParser(Constants.SERVICE_TYPE_ROOMMATE, querystringParms, activity);
		mRoommates = parser.parsePerson();
    }

    /**
     * Handles the logout event - this deletes the row in the backend SQL Server database and invalidates the login credentials
     * @param bsuID
     * @param loginGuid - login guid used to determine whether the user is authorized to retrieve the data from the service handler
     * @param activity - used by the {@link ParserFactory} to retrieve the demo_account shared preference - this will determine what
     * 					 data source to use for the service handler.
     * @throws UnsupportedEncodingException - the encrypted BSU ID has to be encoded in order to pass as a querystring parameter
     */
    public static void initializeLogout(String bsuID, String loginGuid, Activity activity) 
    		throws UnsupportedEncodingException {
    	List<String> querystringParms = new ArrayList<String>(2);
		querystringParms.add(Constants.QUERYSTRING_BSU_ID + URLEncoder.encode(bsuID, "UTF-8"));
		querystringParms.add(Constants.QUERYSTRING_LOGIN_GUID + loginGuid);

		ServiceParser parser = ParserFactory.getParser(Constants.SERVICE_TYPE_LOGOUT, querystringParms, activity);
		parser.parsePerson();
    }

    /**
     * Returns a boolean indicating whether or not the student was authenticated to retrieve the advisor data from the service handler. 
     * If the BSU ID and login guid passed to the service handler do not match the values in the SQL Server backend database, then the XML 
     * will contain an error indicator in the first element. 
     * @return true|false
     */
    public static boolean getAdvisorAuth() {
    	if (mAdvisors.size() > 0) {
    		if (mAdvisors.get(0).getError() != null) {
    			return false;
    		}
    	}
    	
    	return true;
    }

    /**
     * Returns the integer value of the {@link Person} object size
     * @return mAdvisors.size() || 0
     */
    public static int getAdvisorCount() {
    	if (mAdvisors == null) {
    		return 0;
    	} else {
            return mAdvisors.size();
    	}
    }

    /**
     * Returns a {@link Person} object at the index specified
     * @param i - the index of the object to be returned
     * @return mAdvisors.get(i)
     */
    public static Person getAdvisor(int i) {
        return mAdvisors.get(i);
    }

    /**
     * Returns the ArrayList<Person>
     * @return mAdvisors
     */
    public static ArrayList<Person> getAdvisors() {
        return mAdvisors;
    }

    /**
     * Returns a boolean indicating whether or not the student was authenticated to retrieve the classmate data from the service handler. 
     * If the BSU ID and login guid passed to the service handler do not match the values in the SQL Server backend database, then the XML 
     * will contain an error indicator in the first element. 
     * @return true|false
     */
    public static boolean getClassmateAuth() {
    	if (mClassmates.size() > 0) {
    		if (mClassmates.get(0).getError() != null) {
    			return false;
    		}
    	}
    	
    	return true;
    }

    /**
     * Returns the integer value of the {@link Person} object size
     * @return mClassmates.size() || 0
     */
    public static int getClassmateCount() {
    	if (mClassmates == null) {
    		return 0;
    	} else {
            return mClassmates.size();
    	}
    }

    /**
     * Returns a {@link Person} object at the index specified
     * @param i - the index of the object to be returned
     * @return mClassmates.get(i)
     */
    public static Person getClassmate(int i) {
        return mClassmates.get(i);
    }

    /**
     * Returns the ArrayList<Person>
     * @return mClassmates
     */
    public static ArrayList<Person> getClassmates() {
        return mClassmates;
    }

    /**
     * Returns the integer value of the {@link Person} object size
     * @return mInstructors.size() || 0
     */
    public static int getInstructorCount() {
    	if (mInstructors == null) {
    		return 0;
    	} else {
            return mInstructors.size();
    	}
    }

    /**
     * Returns a {@link Person} object at the index specified
     * @param i - the index of the object to be returned
     * @return mInstructors.get(i)
     */
    public static Person getInstructor(int i) {
        return mInstructors.get(i);
    }

    /**
     * Returns the ArrayList<Person>
     * @return mInstructors
     */
    public static ArrayList<Person> getInstructors() {
        return mInstructors;
    }

    /**
     * Returns a boolean indicating whether or not the student was authenticated to retrieve the organization member data from the service handler. 
     * If the BSU ID and login guid passed to the service handler do not match the values in the SQL Server backend database, then the XML 
     * will contain an error indicator in the first element. 
     * @return true|false
     */
    public static boolean getMemberAuth() {
    	if (mMembers.size() > 0) {
    		if (mMembers.get(0).getError() != null) {
    			return false;
    		}
    	}
    	
    	return true;
    }

    /**
     * Returns the integer value of the {@link Person} object size
     * @return mMembers.size() || 0
     */
    public static int getMemberCount() {
    	if (mMembers == null) {
    		return 0;
    	} else {
            return mMembers.size();
    	}
    }

    /**
     * Returns a {@link Person} object at the index specified
     * @param i - the index of the object to be returned
     * @return mMembers.get(i)
     */
    public static Person getMember(int i) {
        return mMembers.get(i);
    }

    /**
     * Returns the ArrayList<Person>
     * @return mMembers
     */
    public static ArrayList<Person> getMembers() {
        return mMembers;
    }

    /**
     * Returns the integer value of the {@link Person} object size
     * @return mPerson.size() || 0
     */
    public static int getPersonCount() {
    	if (mPerson == null) {
    		return 0;
    	} else {
            return mPerson.size();
    	}
    }

    /**
     * Returns a {@link Person} object at the index specified
     * @param i - the index of the object to be returned
     * @return mPerson.get(i)
     */
    public static Person getPerson(int i) {
        return mPerson.get(i);
    }

    /**
     * Returns a boolean indicating whether or not the student was authenticated to retrieve the neighbor data from the service handler. 
     * If the BSU ID and login guid passed to the service handler do not match the values in the SQL Server backend database, then the XML 
     * will contain an error indicator in the first element. 
     * @return true|false
     */
    public static boolean getRoommateAuth() {
    	if (mRoommates.size() > 0) {
    		if (mRoommates.get(0).getError() != null) {
    			return false;
    		}
    	}
    	
    	return true;
    }

    /**
     * Returns the integer value of the {@link Person} object size
     * @return mRoommates.size() || 0
     */
    public static int getRoommateCount() {
    	if (mRoommates == null) {
    		return 0;
    	} else {
            return mRoommates.size();
    	}
    }

    /**
     * Returns a {@link Person} object at the index specified
     * @param i - the index of the object to be returned
     * @return mRoommates.get(i)
     */
    public static Person getRoommate(int i) {
        return mRoommates.get(i);
    }

    /**
     * Returns the ArrayList<Person>
     * @return mRoommates
     */
    public static ArrayList<Person> getRoommates() {
        return mRoommates;
    }

    /**
     * Updates the local database to indicate the "star" status of a connection.  Calls the insert and update methods of the {@link DBAdapter}.
     * @param activity
     * @param firstName
     * @param lastName
     * @param nameSuffix
     * @param isChecked
     * @param bsuID
     * @param starredBSUID
     * @param personType
     */
    public static void starPerson(Activity activity, String firstName, String lastName, String nameSuffix, boolean isChecked, 
    		String bsuID, String starredBSUID, int personType) {
		Crypto c = new Crypto(BSUPrivate.KEY);
		
    	DBAdapter db = new DBAdapter(activity);
    	db.open();

        Cursor data = db.getStarred(bsuID, starredBSUID);
    	activity.startManagingCursor(data);	        

    	// Encrypt the first and last name to store in the SQLite database
    	// This will help protect the identity of the student in the event someone with a rooted phone opens the database and attempts to match
    	// BSU IDs with names
    	firstName = c.encryptAsBase64(firstName.getBytes());
    	lastName = c.encryptAsBase64(lastName.getBytes());
    	nameSuffix = c.encryptAsBase64(nameSuffix.getBytes());
    	
    	// Update the table containing the BSU ID and the star indicator
        if (data.getCount() > 0) { 
        	// Retrieve the values from the cursor
        	int rowID = Integer.parseInt(data.getString(data.getColumnIndexOrThrow(DBAdapter.KEY_ROWID)));
		    
		    // Update the expiration date based on the most recent login
		    db.updateStarred(rowID, bsuID, starredBSUID, firstName, lastName, nameSuffix, isChecked ? 1 : 0, personType);
        }  else {
        	db.insertStarred(bsuID, starredBSUID, firstName, lastName, nameSuffix, isChecked ? 1 : 0, personType); 
        }

        activity.stopManagingCursor(data);
        //data.close();
        db.close(); 

        // Because change listener is set to null during initialization, these won't fire on pageview.
        AnalyticsUtils.getInstance(activity).trackEvent("Connections", isChecked ? "Starred" : "Unstarred", "connection", 0);
    }

    /**
     * Determines the "star" status of a person when the student view the person details. Calls the get methods
     * of the {@link DBAdapter}.
     * @param activity
     * @param bsuID
     * @param starredBSUID
     * @return true|false depending on whether the person has been starred
     */
    // Determine the "star" status of the person based on the student's BSU ID and the connection BSU ID
    public static boolean getPersonStarred(Activity activity, String bsuID, String starredBSUID) {
    	DBAdapter db = new DBAdapter(activity);
    	db.open();
  	
	    // Retrieve the user information based on the BSU ID and the member BSU ID
        Cursor data = db.getStarred(bsuID, starredBSUID);
        boolean starred = false;
        
        activity.startManagingCursor(data);	        

        if (data.getCount() > 0) { 
        	starred = (Integer.parseInt(data.getString(data.getColumnIndexOrThrow(DBAdapter.KEY_STARRED))) != 0);
        }
        
        activity.stopManagingCursor(data);
        //data.close();
        db.close(); 
        
        return starred;
    }
}
